package model

import (
	j_log "config-client-v1/init/j-log"
	"config-client-v1/utils/tools"
	"encoding/json"
	"fmt"
	"github.com/gorilla/websocket"
	"runtime/debug"
	"time"
)

type OPCUAClientConfig struct {
	URL     string `json:"url"`     // 设备URL [opc.tcp://127.0.0.1:49320]
	User    string `json:"user"`    // 账号
	Pwd     string `json:"pwd"`     // 密码
	PFXFile string `json:"pfxfile"` // 证书 tmp/xxx.cert
	ISNM    string `json:"isnm"`    // 是否匿名 [0, 1], 也是字符串的 0 和 1
}
type OPCUAServerConfig struct {
	Port string `json:"port"` // 端口, 字符串的数字
	SXPL string `json:"sxpl"` // 刷新频率, 字符串的数字, 单位ms
}

func (ppe *PPE) RunOPCUAClient() {
	defer func() {
		if err := recover(); err != nil {
			j_log.LogError([]interface{}{"RunOPCClient panic", err})
			fmt.Println(string(debug.Stack()))
		}

		if ppe.RunningState == 3 {
			j_log.LogInfo([]interface{}{"【已停止】", ppe.ProtocolName, ppe.Name})
			ppe.RunningState = 4 // 设备停止
			ppe.UnRegister()
			_ = ppe.UpdateRunningState(4, "设备已停止")
			return
		}

		j_log.LogInfo([]interface{}{ppe.ProtocolName, ppe.Name, "3秒后重连"})
		ppe.RunningState = 0 // 设备异常
		ppe.Detail = "正在尝试重连..."
		_ = ppe.UpdateRunningState(5, "正在尝试重连...")
		time.Sleep(3 * time.Second)

		if ppe.RunningState == 3 {
			j_log.LogInfo([]interface{}{"【已停止】", ppe.ProtocolName, ppe.Name})
			ppe.RunningState = 4 // 设备停止
			ppe.UnRegister()
			_ = ppe.UpdateRunningState(4, "设备已停止")
			return
		}
		ppe.RunOPCUAClient()
	}()
	ppe.Register()
	time.Sleep(1 * time.Second)
	req := OPCWSRequest{
		Route: "opcua/start",
		TS:    tools.GetNow(),
		Params: map[string]interface{}{
			"ppe_id": ppe.ID,
		},
	}
	jsonB, _ := json.Marshal(&req)
	err := OPCWSClient.WriteMessage(websocket.TextMessage, jsonB)
	if err != nil {
		j_log.LogError([]interface{}{"OPCWSClient 异常", err.Error()})
		return
	}

	startTime := time.Now()
	for {
		time.Sleep(100 * time.Millisecond)
		if ppe.RunningState == 2 {
			break
		}
		if time.Since(startTime) > time.Second*3 {
			j_log.LogError([]interface{}{fmt.Sprintf("设备启动超时, %s:%s", ppe.ProtocolName, ppe.Name)})
			return
		}
	}
	j_log.LogInfo([]interface{}{fmt.Sprintf("【已启动】%s:%s", ppe.ProtocolName, ppe.Name)})
	ppe.Detail = "已启动"
	_ = ppe.UpdateRunningState(2, "已启动")
	// 首次连接成功时,更新记录时间, 下次更新只有在收到 opcua/status (状态查询,也当心跳包使用) 返回的data等于1时才更新时间
	ppe.OPCClientLastTime = time.Now().Unix()
	counter := 1
	for {
		select {
		default:
			if ppe.RunningState == 1 {
				return
			}
			if ppe.RunningState == 2 && (time.Now().Unix()-ppe.OPCClientLastTime > 10) {
				ppe.RunningState = 1
				j_log.LogError([]interface{}{fmt.Sprintf("设备超时未响应,即将重启 %s:%s", ppe.ProtocolName, ppe.Name)})
				return
			}
			if ppe.RunningState == 3 {
				return
			}
			// 状态查询,心跳
			if counter%3 == 0 {
				req = OPCWSRequest{
					Route: "opcua/status",
					TS:    tools.GetNow(),
					Params: map[string]interface{}{
						"ppe_id": ppe.ID,
					},
				}
				jsonB, _ = json.Marshal(&req)
				err = OPCWSClient.WriteMessage(websocket.TextMessage, jsonB)
				if err != nil {
					j_log.LogError([]interface{}{"心跳包发送失败, OPCWSClient 异常", err.Error()})
				}
				//j_log.LogInfo([]interface{}{fmt.Sprintf("【心跳】%s:%s", ppe.ProtocolName, ppe.Name)})
			}
			counter++
			time.Sleep(1000 * time.Millisecond)
		}
	}
}

func (ppe *PPE) RunOPCUAServer() {
	defer func() {
		if err := recover(); err != nil {
			j_log.LogError([]interface{}{"RunOPCUAServer panic", err})
			fmt.Println(string(debug.Stack()))
		}

		if ppe.RunningState == 3 {
			j_log.LogInfo([]interface{}{"【已停止】", ppe.ProtocolName, ppe.Name})
			ppe.RunningState = 4
			ppe.Detail = "设备已停止"
			ppe.UnRegister()
			_ = ppe.UpdateRunningState(ppe.RunningState, ppe.Detail)
			return
		}

		ppe.RunningState = 5 // 设备异常
		ppe.Detail = "正在尝试重连"
		j_log.LogInfo([]interface{}{ppe.ProtocolName, ppe.Name, ppe.Detail})
		_ = ppe.UpdateRunningState(ppe.RunningState, ppe.Detail)
		time.Sleep(3 * time.Second)

		if ppe.RunningState == 3 {
			j_log.LogInfo([]interface{}{"【已停止】", ppe.ProtocolName, ppe.Name})
			ppe.RunningState = 4
			ppe.Detail = "设备已停止"
			ppe.UnRegister()
			_ = ppe.UpdateRunningState(ppe.RunningState, ppe.Detail)
			return
		}
		ppe.RunOPCUAServer()
	}()
	ppe.Register()
	time.Sleep(1 * time.Second)
	req := OPCWSRequest{
		Route: "opcuaserver/start",
		TS:    tools.GetNow(),
		Params: map[string]interface{}{
			"ppe_id": ppe.ID,
		},
	}
	jsonB, _ := json.Marshal(&req)
	err := OPCWSClient.WriteMessage(websocket.TextMessage, jsonB)
	if err != nil {
		j_log.LogError([]interface{}{"OPCWSClient 异常", err.Error()})
		return
	}

	startTime := time.Now()
	for {
		time.Sleep(100 * time.Millisecond)
		if ppe.RunningState == 2 {
			break
		}
		if time.Since(startTime) > time.Second*3 {
			j_log.LogError([]interface{}{fmt.Sprintf("设备启动超时, %s:%s", ppe.ProtocolName, ppe.Name)})
			return
		}
	}
	j_log.LogInfo([]interface{}{fmt.Sprintf("【已启动】%s:%s", ppe.ProtocolName, ppe.Name)})
	_ = ppe.UpdateRunningState(ppe.RunningState, ppe.Detail)
	// 首次连接成功时,更新记录时间, 下次更新只有在收到 opcuaserver/status (状态查询,也当心跳包使用) 返回的data等于1时才更新时间
	ppe.OPCClientLastTime = time.Now().Unix()
	counter := 1
	for {
		select {
		default:
			if ppe.RunningState == 1 {
				return
			}
			if ppe.RunningState == 2 && (time.Now().Unix()-ppe.OPCClientLastTime > 10) {
				ppe.RunningState = 1
				j_log.LogError([]interface{}{fmt.Sprintf("设备超时未响应,即将重启 %s:%s", ppe.ProtocolName, ppe.Name)})
				return
			}
			if ppe.RunningState == 3 {
				return
			}
			// 状态查询,心跳
			if counter%3 == 0 {
				req = OPCWSRequest{
					Route: "opcuaserver/status",
					TS:    tools.GetNow(),
					Params: map[string]interface{}{
						"ppe_id": ppe.ID,
					},
				}
				jsonB, _ = json.Marshal(&req)
				err = OPCWSClient.WriteMessage(websocket.TextMessage, jsonB)
				if err != nil {
					j_log.LogError([]interface{}{"心跳包发送失败, OPCWSClient 异常", err.Error()})
				}
				//j_log.LogInfo([]interface{}{fmt.Sprintf("【心跳】%s:%s", ppe.ProtocolName, ppe.Name)})
			}
			counter++
			time.Sleep(1000 * time.Millisecond)
		}
	}
}
